#include "../head/server.h"

// 处理puts命令，即接收文件
int puts_work(int net_fd, char *user_name, MYSQL *mysql)
{

	train_t train;
	bzero(&train, sizeof(train));

	// 接收文件名
	char file_name[1024] = {0};
	int file_name_len;
	recv(net_fd, &file_name_len, sizeof(int), MSG_WAITALL);
	recv(net_fd, file_name, file_name_len, MSG_WAITALL);

	printf("要创建的文件名为: %s\n", file_name);

	// 接收文件的hash值
	recv(net_fd, &train.length, sizeof(int), MSG_WAITALL);
	recv(net_fd, train.data, train.length, MSG_WAITALL);
	char file_hash[1024] = {0};
	strcpy(file_hash, train.data);
	printf("文件哈希值为：%s\n", file_hash);

	int check_hash_ret = check_hash_existence(mysql, file_hash);
	if (check_hash_ret == 0)
	{
		printf("表中没有这个哈希值，接收文件。\n");
		// 先给客户端发送train.len == 1，告诉客户端要上传
		bzero(&train, sizeof(train));
		train.length = 1;
		send(net_fd, &train, sizeof(train.length) + train.length, MSG_NOSIGNAL);

		// 下面开始接受文件
		//  创建文件
		char full_path[1024] = {0};
		getparameter("root_path", full_path);
		strcat(full_path, "/");
		strcat(full_path, file_name);
		printf("%s\n", full_path);
		int file_fd = open(full_path, O_RDWR | O_CREAT, 0666);
		ERROR_CHECK(file_fd, -1, "open");

		// 读取文件的长度
		off_t file_size;
		recv(net_fd, &file_size, sizeof(off_t), MSG_WAITALL);
		printf("下载到的文件的大小为：%ld\n", file_size);

		// 读取客户端传过来的内容，并且写入文件
		if (file_size >= BIG_FILE)
		{
			// 大文件
			ftruncate(file_fd, file_size);
			char *p = (char *)mmap(NULL, file_size, PROT_READ | PROT_WRITE, MAP_SHARED, file_fd, 0);
			recv(net_fd, p, file_size, MSG_WAITALL);
			munmap(p, file_size);
		}
		else
		{
			// 小文件
			while (1)
			{
				recv(net_fd, &train.length, sizeof(train.length), MSG_WAITALL);
				if (train.length == 0)
				{
					break;
				}
				recv(net_fd, train.data, train.length, MSG_WAITALL);
				write(file_fd, train.data, train.length);
			}
		}

		close(file_fd);

		// 接收完文件要去file_table里添加这一条数据
		// const char *filename = user_name;
		const char *file_type = "File";
		const char *hash_value = file_hash;
		if (insert_file_table_record(mysql, file_name, file_type, hash_value) != 0)
		{
			printf("file_table表中插入数据失败。\n");
		}
		else
		{
			printf("file_table表中数据插入成功。\n");
		}
	}
	else if (check_hash_ret > 0)
	{
		printf("表中有这个哈希值，极速秒传！\n");
		// 先给客户端发送train.len == 0，意思是告诉客户端这次是极速秒传，不用上传文件了
		bzero(&train, sizeof(train));
		train.length = strlen("topspeed");
		memcpy(train.data, "topspeed", train.length);
		send(net_fd, &train.length, sizeof(train.length) + train.length, MSG_NOSIGNAL);
	}
	else
	{
		// 先给客户端发送train.len = -1，意思是告诉客户端服务器故障
		bzero(&train, sizeof(train));
		train.length = strlen("error");
		memcpy(train.data, "error", train.length);
		send(net_fd, &train.length, sizeof(train.length), MSG_NOSIGNAL);
	}

	printf("文件下载完成！\n");
	printf("正在更新数据库中的表！\n");

	// 最后需要去all_user_file表中添加这一条数据
	// 为了知道该文件所在的文件路径，需要先去user_info表中查current_path，然后拼接上文件名
	char *current_path = get_current_path_by_username(mysql, user_name);
	if (current_path == NULL)
	{
		printf("查询失败。\n");
	}
	else
	{
		printf("用户名 '%s' 对应的当前路径是 '%s'。\n", user_name, current_path);
	}
	char path[1024] = {0};
	strcat(strcpy(path, current_path), file_name); // 给file_path赋值的path拼接完成了

	// 根据当前路径，找到当前所在目录的id
	int path_len = strlen(path);
	int i;
	for (i = path_len - 1; i > 0; i--)
	{
		if (path[i] == '/')
		{ // 从后往前遍历找到第一个'/'
			break;
		}
	}
	char parent_dir_name[1024] = {0};
	if (i)
	{
		// 把从后往前第一个'/'后面的内容赋值给file_name
		strcpy(parent_dir_name, (path + i + 1));
	}
	else
	{
		// i=0意味着当前目录是'/'
		strcpy(parent_dir_name, "/");
	}

	int id = get_id_by_username_and_filename(mysql, user_name, parent_dir_name);
	if (id == -1)
	{
		printf("查询失败。\n");
	}
	else
	{
		printf("用户名 '%s' 和文件名 '%s' 对应的记录的 ID 是 %d。\n", user_name, parent_dir_name, id);
	}

	// const char *file_name = file_name;    //上面已经有现成的file_name了
	// const char *username = user_name;
	int parent_id = id;
	const char *file_path = path;
	const char *file_type = "File";
	const char *hash_value = file_hash;

	if (insert_all_user_file_record(mysql, file_name, user_name, parent_id, file_path, file_type, hash_value) != 0)
	{
		printf("插入数据失败。\n");
	}
	else
	{
		printf("数据插入成功。\n");
	}

	printf("all_user_file表和file_table表已更新\n");

	return 0;
}

// 下面五个函数在头文件中有描述用法和声明
int check_hash_existence(MYSQL *conn, const char *hash)
{
	MYSQL_RES *res;
	MYSQL_ROW row;

	char query[256];																 // 存储构造的查询语句
	sprintf(query, "SELECT COUNT(*) FROM file_table WHERE hash_value = '%s'", hash); // 将格式化的字符串写入query数组
	printf("%s\n", query);
	if (mysql_query(conn, query) != 0)
	{
		printf("%s\n", mysql_error(conn));
		return -1;
	}

	res = mysql_store_result(conn);
	if (res == NULL)
	{
		printf("%s\n", mysql_error(conn));
		return -1;
	}

	row = mysql_fetch_row(res);
	if (row == NULL)
	{
		printf("2\n");
		mysql_free_result(res);
		return -1;
	}
	printf("%s\n", row[0]);
	mysql_free_result(res);

	return atoi(row[0]);
}

int insert_file_table_record(MYSQL *conn, const char *filename, const char *file_type, const char *hash_value)
{
	char query[1024];
	sprintf(query, "INSERT INTO file_table (filename, file_type, hash_value) VALUES ('%s', '%s', '%s')",
			filename, file_type, hash_value);

	if (mysql_query(conn, query) != 0)
	{
		printf("%s\n", mysql_error(conn));
		return 1;
	}

	return 0;
}

int insert_all_user_file_record(MYSQL *conn, const char *file_name, const char *user_name, int parent_id, const char *file_path, const char *file_type, const char *hash_value)
{
	char query[1024];
	sprintf(query, "INSERT INTO all_user_file (filename, username, parent_id, file_path, file_type, hash_value) VALUES ('%s', '%s', %d, '%s', '%s', '%s')",
			file_name, user_name, parent_id, file_path, file_type, hash_value);

	if (mysql_query(conn, query) != 0)
	{
		printf("%s\n", mysql_error(conn));
		return 1;
	}

	return 0;
}

char *get_current_path_by_username(MYSQL *conn, const char *username)
{
	char query[256];
	sprintf(query, "SELECT current_path FROM user_info WHERE username = '%s'", username);

	if (mysql_query(conn, query) != 0)
	{
		printf("1\n");
		printf("%s\n", mysql_error(conn));
		return NULL;
	}

	MYSQL_RES *res = mysql_store_result(conn);
	if (res == NULL)
	{
		printf("2\n");
		printf("%s\n", mysql_error(conn));
		return NULL;
	}

	MYSQL_ROW row = mysql_fetch_row(res);
	if (row == NULL)
	{
		mysql_free_result(res);
		printf("未找到与用户名 '%s' 对应的记录。\n", username);
		return NULL;
	}

	char *current_path = strdup(row[0]);

	mysql_free_result(res);

	return current_path;
}

int get_id_by_username_and_filename(MYSQL *conn, const char *user_name, const char *filename)
{
	char query[256];
	sprintf(query, "SELECT id FROM all_user_file WHERE username = '%s' AND filename = '%s'", user_name, filename);

	if (mysql_query(conn, query) != 0)
	{
		printf("%s\n", mysql_error(conn));
		return -1;
	}

	MYSQL_RES *res = mysql_store_result(conn);
	if (res == NULL)
	{
		printf("%s\n", mysql_error(conn));
		return -1;
	}

	MYSQL_ROW row = mysql_fetch_row(res);
	if (row == NULL)
	{
		mysql_free_result(res);
		printf("未找到与用户名 '%s' 和文件名 '%s' 对应的记录。\n", user_name, filename);
		return -1;
	}

	int id = atoi(row[0]);

	mysql_free_result(res);

	return id;
}
